package research.ui.editors.tableeditors;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.jface.viewers.*;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.*;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.*;

import research.entity.Entity;
import research.entity.EntityFactory;
import research.entity.EntityType;
import research.ui.editors.tableeditors.EntityList;
import research.ui.editors.tableeditors.IEntityTableListener;

public abstract class EntityTableEditor {

	private EntityType type;
	private Table table;
	protected TableViewer tableViewer;
	protected EntityList list;
	private boolean isEditable;
	
	private List<ColumnData> columns = new ArrayList<ColumnData>();
	
	protected class ColumnData {
		public String name;
		public int width;
		public CellEditor editor;

		public ColumnData(String name, int width, CellEditor editor) {
			super();
			this.name = name;
			this.width = width;
			this.editor = editor;
		}
	}
	
	public EntityTableEditor(EntityType type) {
		this.type = type;
		this.isEditable = true;
	}
	
	public EntityTableEditor(EntityType type, boolean isEditable) {
		this.type = type;
		this.isEditable = isEditable;
	}
	
	public void setLabelProvider(IBaseLabelProvider labelProvider) {
		tableViewer.setLabelProvider(labelProvider);
	}

	public void setCellModifier(ICellModifier cellModifier) {
		tableViewer.setCellModifier(cellModifier);
	}

	public void setSorter(ViewerSorter sorter) {
		tableViewer.setSorter(sorter);
	}

	public void dispose() {
		tableViewer.getLabelProvider().dispose();
	}
	
	public void setInput(List<Entity> list)
	{
		this.list = new EntityList(list);
		tableViewer.setInput(this.list);		
	}
	
	public void addModifyListener(IEntityTableListener listener) {
		this.list.addChangeListener(listener);
	}
	
	public void removeModifyListener(IEntityTableListener listener) {
		this.list.removeChangeListener(listener);
	}

	class EntityContentProvider implements IStructuredContentProvider,
			IEntityTableListener {
		
		public void inputChanged(Viewer v, Object oldInput, Object newInput) {
			if (newInput != null)
				((EntityList) newInput).addChangeListener(this);
			if (oldInput != null)
				((EntityList) oldInput).removeChangeListener(this);
		}

		public void dispose() {
			list.removeChangeListener(this);
		}

		public Object[] getElements(Object parent) {
			return list.getEntities().toArray();
		}

		public void add(Entity par) {
			tableViewer.add(par);
		}

		public void remove(Entity par) {
			tableViewer.remove(par);
		}

		public void update(Entity par) {
			tableViewer.update(par, null);
		}
	}

	protected void render(Composite composite) {
		GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL
				| GridData.FILL_BOTH);
		composite.setLayoutData(gridData);

		GridLayout layout = new GridLayout(3, false);
		layout.marginWidth = 4;
		composite.setLayout(layout);

		createTable(composite);
		
		tableViewer = new TableViewer(table);
		tableViewer.setUseHashlookup(true);
		tableViewer.setContentProvider(new EntityContentProvider());

		if (isEditable)
			createButtons(composite);
		
		this.columns = getColumnsData();
		
		renderColumns();
	}

	public void renderColumns() {
		TableColumn column;
		int idx = 0;
		
		for (ColumnData columnData : columns) {
			column = new TableColumn(table, SWT.LEFT, idx++);
			column.setText(columnData.name);
			column.setWidth(columnData.width);
		}
		
		tableViewer.setColumnProperties(getColumnNames().toArray(new String[] {}));
		tableViewer.setCellEditors(getColumnEditors().toArray(new CellEditor[] {}));
	}
	
	public void rerenderColumnEditors() {
		
		this.columns = getColumnsData();
		tableViewer.setCellEditors(getColumnEditors().toArray(new CellEditor[] {}));
	}

	private void createTable(Composite parent) {
		int style = SWT.SINGLE | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL
				| SWT.FULL_SELECTION | SWT.HIDE_SELECTION;

		table = new Table(parent, style);

		GridData gridData = new GridData(GridData.FILL_BOTH);
		gridData.widthHint = 200;
		gridData.heightHint = 100;
		gridData.grabExcessVerticalSpace = true;
		gridData.horizontalSpan = 3;
		table.setLayoutData(gridData);

		table.setLinesVisible(true);
		table.setHeaderVisible(true);
	}
	
	private void createButtons(Composite parent) {

		Button add = new Button(parent, SWT.PUSH | SWT.CENTER);
		add.setText("Добавить");

		GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
		gridData.widthHint = 80;
		add.setLayoutData(gridData);
		add.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				list.add(getNew());
			}
		});

		Button delete = new Button(parent, SWT.PUSH | SWT.CENTER);
		delete.setText("Удалить");
		gridData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
		gridData.widthHint = 80;
		delete.setLayoutData(gridData);
		delete.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				Entity par = (Entity) ((IStructuredSelection) tableViewer
						.getSelection()).getFirstElement();
				if (par != null) {
					list.removeValue(par);
				}
			}
		});
	}

	public List<String> getColumnNames() {
		List<String> res = new ArrayList<String>();
		for (ColumnData data : columns) {
			res.add(data.name);
		}
		return res;
	}
	
	public List<CellEditor> getColumnEditors() {
		List<CellEditor> res = new ArrayList<CellEditor>();
		for (ColumnData data : columns) {
			res.add(data.editor);
		}
		return res;
	}

	public ISelection getSelection() {
		return tableViewer.getSelection();
	}

	public EntityList getEntityList() {
		return list;
	}

	public Control getControl() {
		return table.getParent();
	}
	
	protected CellEditor createTextCellEditor(int textLimit) {
		TextCellEditor textEditor = new TextCellEditor(table);
		((Text) textEditor.getControl()).setTextLimit(textLimit);
		return textEditor;
	}
	
	protected CellEditor createComboBoxCellEditor(String[] items) {
		ComboBoxCellEditor comboEditor = new ComboBoxCellEditor(table, items, SWT.READ_ONLY);
		return comboEditor;
	}
	
	protected CellEditor createCheckBoxCellEditor() {
		CheckboxCellEditor checkBoxEditor = new CheckboxCellEditor(table);
		return checkBoxEditor;
	}
	
	protected abstract List<ColumnData> getColumnsData();
	
	private Entity getNew() {
		return EntityFactory.getNew(type);
	}

	public void refresh() {
		tableViewer.refresh();
	}
}